package iptux;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.lang.management.ManagementFactory;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import iptux.StaticConsts;

/**
 * Title: class Utils<br>
 * Description: Utils class<br>
 * Copyright: MIT open source protocol<br>
 * @author cwll<cwll2009@126.com>
 * @version 1.0.0
 */
public class Utils {
	
	static int packetNum = 1;
	static Iptux mainDlg = null;
	
	/**
	 * Get the local IP addresses, return a ArrayList<String> of addresses.
	 * @return iplist is a ArrayList of the string, each one is a  IP address.
	 */
	public static ArrayList<String> GetLocalIPAddress(){
		ArrayList<String>  iplist = new ArrayList<String>();
		Enumeration<NetworkInterface> allNetInterfaces;
		try {
			allNetInterfaces = NetworkInterface.getNetworkInterfaces();
		} catch (SocketException e) {
			e.printStackTrace();
			return iplist;
		}
		InetAddress ip = null;
		while (allNetInterfaces.hasMoreElements()){
			NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();
			Enumeration<InetAddress> addresses = netInterface.getInetAddresses();
			while (addresses.hasMoreElements())	{
				ip = (InetAddress) addresses.nextElement();
				if (ip != null && ip instanceof Inet4Address){
					if( !ip.isLoopbackAddress() ){
						iplist.add(ip.getHostAddress());
					}
				} 
			}
		}
		//iplist.remove("127.0.0.1");
		return iplist;
	}
	
	/**
	 * Make the IPMSG header. auto makes Packet Number.
	 * @param Command control command
	 * @return The IPMSG header of string
	 */
	public static String MakeCommand(int Command){
		String Username = System.getProperty("user.name");
		String Hostname = System.getProperty("os.name");
		//String Nickname = "iptux on " + Hostname;
		
		String buf="";
		buf+=String.format("%s", StaticConsts.IPTUX_VERSION);
		//Packet Number
		buf = buf + ":" + getPacketNum();
		buf+=String.format(":%s",Username);
		buf+=String.format(":%s",Hostname);
		buf+=String.format(":%d:",Command);
		return buf;
	}
	
	/**
	 * Make the IPMSG header.
	 * @param Command control command
	 * @param PacketNum  Packet number in string
	 * @return The IPMSG header of string
	 */
	public static String MakeCommand(int Command,String packetNum){
		String Username = System.getProperty("user.name");
		String Hostname = System.getProperty("os.name");
		//String Nickname = "iptux on " + Hostname;
		
		//String buf = String.format("%s", StaticConsts.IPTUX_VERSION);
		String buf = new String(StaticConsts.IPTUX_VERSION);
		//Packet Number
		buf = buf + ":" + packetNum;
		buf+=String.format(":%s",Username);
		buf+=String.format(":%s",Hostname);
		buf+=String.format(":%d:",Command);
		return buf;
	}
	
	public static String getPacketNumFromCommand(String Command){
		String PacketNum = Command.split(":")[1];
		return PacketNum;
	}
	
	/**
	 * Convert string from unicode to GB18030
	 * @param uniStr
	 * @return
	 */
	public static String uniToGb(String uniStr) {
		String gbStr = "";
		if (uniStr == null) {
			uniStr = "";
		}
		try {
			byte[] tempByte = uniStr.getBytes("UTF-8");
			gbStr = new String(tempByte, "GB18030");
		} catch (Exception ex) {
		}
		return gbStr;
	}

	/**
	 * Convert string from GB18030 to unicode
	 * @param gbStr
	 * @return
	 */
	public static String gbToUni(String gbStr) {
		String uniStr = "";
		if (gbStr == null) {
			gbStr = "";
		}
		try {
			byte[] tempByte = gbStr.getBytes("GBK");
			uniStr = new String(tempByte, "UTF-8");
		} catch (Exception ex) {
		}
		return uniStr;
	}
	
	/**
	 * Get the uptime  
	 * @return millisecond of string
	 */
	public static String getPacketNum(){
		//long uptime = System.currentTimeMillis();
		//return Long.toString(uptime);
		packetNum++;
		return Integer.toString(packetNum);
	}
	
	/**
	 * get file or folder size
	 * @param file
	 * @return size in byte
	 */
	public static long getDirSize(File file) {     
        //判断文件是否存在   
		long size = 0;
        if (file.exists()) {     
            //如果是目录则递归计算其内容的总大小    
            if (file.isDirectory()) {     
                File[] children = file.listFiles();     
                if(children != null){
					for (File f : children)
						size += getDirSize(f);
                }
                return size; 
            } else {//如果是文件则直接返回其大小         
                return file.length();      
            }     
        } else {     
            //System.out.println(file.getPath()+"文件或者文件夹不存在，请检查路径是否正确！");     
            return 0;     
        }     
    }
	
	/**
	 * test if the filePathName is exist, either regular file or directory.
	 * If the file name exist create a new file with the name as: file(1).ext, file(2).ext .
	 * @param filePathName
	 * @return the new file name related to the filePathName and is not exist.
	 */
	public static String generateFileName(String filePathName){
		String pathName = "";
		File file = new File(filePathName);
		while(file.exists()){
			String name = file.getName();
			String path = file.getParent();
			String extention = "";
			String realName = name;
			if (name.lastIndexOf(".") > 0){
				extention = name.substring(name.lastIndexOf(".")+1,name.length());
				realName = name.substring(0,name.lastIndexOf("."));
			}
			int prefixLeft = name.lastIndexOf("(");
			int prefixRight = name.lastIndexOf(")");
			if((prefixLeft > 0) && (prefixRight > prefixLeft)){
				int autoOrder = -1;
				try{
					String num = name.substring(prefixLeft+1, prefixRight);
					autoOrder = Integer.valueOf(num);
				}catch(Exception e){
					realName = realName + "(1)";
					if (extention.equals("")){
						pathName = path + File.separator + realName;
					}else{
						pathName = path + File.separator + realName + "." + extention;
					}
					return pathName;
				}
				autoOrder = autoOrder + 1;
				realName = name.substring(0, prefixLeft);
				pathName = path + File.separator + realName + "(" 
						+ Integer.toString(autoOrder) + ")";
				if(!extention.equals("")){
					pathName = pathName + ".";
				}
				pathName = pathName + extention;
				file = new File(pathName);
			}else{
				pathName = path + File.separator + realName + "(1)";
				if(!extention.equals("")){
					pathName = pathName + ".";
				}
				pathName = pathName + extention;
				file = new File(pathName);
			}
		}
		return pathName;
	}
	
	/**
	 * read specified bytes from InputStreamReader.
	 * @param reader the InputStreamReader object
	 * @param buf  the char buffer
	 * @param count  the count want to read , this param should small than the length of buffer
	 * @return the buffer
	 */
	public static char[] readSpecifiedBytes(InputStreamReader reader,char[] buf,int count){
		int readCount = 0;
		while (readCount < count) {
			try {
				readCount += reader.read(buf, readCount, count - readCount);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return buf;
	}
	
	/**
	 * read specified bytes from InputStreamReader.
	 * @param reader the InputStreamReader object
	 * @param buf  the byte buffer
	 * @param count  the count want to read , this param should small than the length of buffer
	 * @return the buffer
	 */
	public static byte[] readSpecifiedBytes(InputStream reader,byte[] buf,int count){
		int readCount = 0;
		while (readCount < count) {
			try {
				readCount += reader.read(buf, readCount, count - readCount);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return buf;
	}
	
	
	/**
	 * make a string as the format of 
	 * headerSize:fileName:fileLength:fileAttribute:
	 * @param pathname of the file to make header
	 * @return  byte encode to configged encoding
	 */
	public static byte[] makeFileSendStreamHeader(String  filePath,String encoding){
		String header = "";
		String headerSize="";
		//String encoding = mainDlg.configer.msgEncoding;
		if(filePath == null){
			header = ":.:0:";
			header = header + Integer.toHexString(StaticConsts.IPMSG_FILE_RETPARENT) + ":";
			headerSize = String.format("%04x", header.length()+4);
			header = headerSize + header;
			try {
				return header.getBytes(encoding);
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
		}
		
		File file = new File(filePath);
		int fileAttr;
		
		header = ":" + file.getName();

		if(file.isFile()){
			header = header +  String.format(":%x",file.length());
			fileAttr = StaticConsts.IPMSG_FILE_REGAR;
		}else{
			long fileSize = Utils.getDirSize(file);
			fileSize = 0;
			header = header + String.format(":%x", fileSize);
			fileAttr = StaticConsts.IPMSG_FILE_DIR;
		}
		header = header + String.format(":%x",fileAttr) + ":";
		
		try {
			byte[] headByte = header.getBytes(encoding);
			headerSize = String.format("%04x", header.getBytes(encoding).length+4);
			byte[] headSizeByte = headerSize.getBytes(encoding);
			byte[] headTotalByte = new byte[headByte.length + headSizeByte.length];
			System.arraycopy(headSizeByte,0,headTotalByte,0,headSizeByte.length);
			System.arraycopy(headByte,0,headTotalByte,headSizeByte.length,headByte.length);
			return headTotalByte;
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * Convert a file size byte to user friendly string. 
	 * @param size file size of long integer
	 * @return  string file size, no support file size larger than 1024PB,
	 */
	public static String longSizeToUISize(long size){
		String uiSize = "0K";
		float fileSize =  Float.parseFloat(String.valueOf(size));
		fileSize = fileSize / 1024;
		if(fileSize < 1024){
			uiSize = String.format("%.2fKB", fileSize);
			return uiSize;
		}
		fileSize = fileSize / 1024;
		if(fileSize < 1024){
			uiSize = String.format("%.2fMB", fileSize);
			return uiSize;
		}
		fileSize = fileSize / 1024;
		if(fileSize < 1024){
			uiSize = String.format("%.2fGB", fileSize);
			return uiSize;
		}
		fileSize = fileSize / 1024;
		if(fileSize < 1024){
			uiSize = String.format("%.2fPB", fileSize);
			return uiSize;
		}
		return uiSize;
	}
	
	/**
	 * delete a item in String array.
	 * @param strArray
	 * @param index
	 * @return
	 */
	public static String[] deleteStringArrayItem(String[] strArray,int index){
		String[] result = new String[strArray.length-1];
		if(index == 0){
			System.arraycopy(strArray, 1, result, 0, strArray.length - 1);
		}else if(index == (strArray.length -1)){
			System.arraycopy(strArray, 0, result, 0, strArray.length - 1);
		}else{
			System.arraycopy(strArray, 0, result, 0, index);
			System.arraycopy(strArray, index + 1, result, index, strArray.length - index - 1);
		}
		return result;
	}
	
	/**
	 * test if the two ip address is in the same subnet.
	 * @param ip1
	 * @param ip2
	 * @return
	 */
	public static boolean sameSubnet(String ip1,String ip2){
		boolean isSame = false;
		if((ip1 == null) || (ip1.equals("null"))){
			return false;
		}
		if((ip2 == null) || (ip2.equals("null"))){
			return false;
		}
		String subnet1 = ip1.substring(0, ip1.lastIndexOf("."));
		String subnet2 = ip2.substring(0, ip2.lastIndexOf("."));		
		if(subnet1.equals(subnet2)){
			isSame = true;
		}else{
			isSame = false;
		}
		return isSame;
	}
	
	
	/**
	 * Read image from jar file to a buffer
	 * @param path The relative path in jar "/" is the root of jar
	 * @return
	 */
	public static byte[] readImageFromJar(String path){
		byte[] buffer = null;
		int size = 0;
		Object test = new Object();
		InputStream is = test.getClass().getResourceAsStream(path);
		try {
			size = is.available();
			buffer = new byte[size];
			is.read(buffer);
			return buffer;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return buffer;
	}
	
	/**
	 * List a sub path of jar file. 
	 * @param path The sub path,do not start and end with splash, for example pixmaps/icon is OK.
	 * @return all file path is this path
	 */
	public static ArrayList<String> ListJarFile(String path){
        JarFile jarFile = null;
        Enumeration<JarEntry> jarEntrys = null;
        String jarName = "";
        if(isDebug()){
        	//if application run in debug mode,read icon files from a jar file that contains the icon.
        	//jar file should be put in the application's debug bin folder. For example:
        	//"~/workspace1/iptux/bin/iptux.jar"
        	Object test = new Object();
        	jarName = test.getClass().getResource("/iptux.jar").getPath();
        }else{
        	jarName = System.getProperty("java.class.path");
        }
		try {
			jarFile = new JarFile(jarName);
			jarEntrys = jarFile.entries();
		} catch (IOException e) {
			e.printStackTrace();
		}

        ArrayList<String> entriesList = new ArrayList<String>();
        while(jarEntrys.hasMoreElements()){
            JarEntry jarEntry = jarEntrys.nextElement();
            if((jarEntry.getName().indexOf(path) == 0) && (!jarEntry.getName().equals(path))){
            	entriesList.add("/"+jarEntry.getName());
            }
        }
        try {
			jarFile.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
        return entriesList;
    }
	
	/**
	 * Test is application run in debug mode.
	 * @return
	 *  This function's source code is copy from internet
	 *	author：RednaxelaFX
	 *	url：http://www.zhihu.com/question/30673515/answer/49146504
	 */
	public static boolean isDebug(){
		List<String> args = ManagementFactory.getRuntimeMXBean().getInputArguments();
		boolean isDebug = false;
		for (String arg : args) {
		  if (arg.startsWith("-Xrunjdwp") || arg.startsWith("-agentlib:jdwp")) {
		    isDebug = true;
		    break;
		  }
		}
		return isDebug;
	}
	
}
